﻿//StrategyParam.cs
//Copyright (c) 2013 StockSharp LLC, all rights reserved.
//This code module is part of StockSharp library.
//This code is licensed under the GNU GENERAL PUBLIC LICENSE Version 3.
//See the file License.txt for the license details.
//More info on: http://stocksharp.com

namespace StockSharp.Algo.Strategies
{
	using System;

	using Ecng.Common;

	/// <summary>
	/// Параметр стратегии.
	/// </summary>
	public interface IStrategyParam
	{
		/// <summary>
		/// Название параметра.
		/// </summary>
		string Name { get; }

		/// <summary>
		/// Значение параметра.
		/// </summary>
		object Value { get; set; }
	}

	/// <summary>
	/// Обертка для типизированного доступа к параметру стратегии.
	/// </summary>
	/// <typeparam name="T">Тип значения параметра.</typeparam>
	public class StrategyParam<T> : IStrategyParam
	{
		private static readonly bool _defaultAllowNullValue;

		static StrategyParam()
		{
			_defaultAllowNullValue = false;

			if (typeof(T).IsNullable())
				_defaultAllowNullValue = true;
		}

		private readonly Strategy _strategy;

		/// <summary>
		/// Создать <see cref="StrategyParam{T}"/>.
		/// </summary>
		/// <param name="strategy">Стратегия.</param>
		/// <param name="name">Название параметра.</param>
		public StrategyParam(Strategy strategy, string name)
			: this(strategy, name, default(T))
		{
		}

		/// <summary>
		/// Создать <see cref="StrategyParam{T}"/>.
		/// </summary>
		/// <param name="strategy">Стратегия.</param>
		/// <param name="name">Название параметра.</param>
		/// <param name="initialValue">Первоначальное значение.</param>
		public StrategyParam(Strategy strategy, string name, T initialValue)
		{
			if (strategy == null)
				throw new ArgumentNullException("strategy");

			if (name.IsEmpty())
				throw new ArgumentNullException("name");

			_strategy = strategy;
			Name = name;
			_value = initialValue;

			_strategy.Parameters.Add(this);
		}

		/// <summary>
		/// Название параметра.
		/// </summary>
		public string Name { get; private set; }

		private bool _allowNull = _defaultAllowNullValue;

		/// <summary>
		/// Возможно ли в <see cref="Value"/> хранить значение, равное null.
		/// </summary>
		public bool AllowNull
		{
			get { return _allowNull; }
			set { _allowNull = value; }
		}

		private T _value;

		/// <summary>
		/// Значение параметра.
		/// </summary>
		public T Value
		{
			get
			{
				return _value;
			}
			set
			{
				if (!AllowNull && value.IsNull())
					throw new ArgumentNullException("value");

				if (_value.Compare(value) == 0)
					return;

				_value = value;
				_strategy.RaiseParametersChanged(Name);
			}
		}

		object IStrategyParam.Value
		{
			get { return Value; }
			set { Value = (T)value; }
		}
	}

	/// <summary>
	/// Вспомогательный класс для с <see cref="StrategyParam{T}"/>.
	/// </summary>
	public static class StrategyParamHelper
	{
		/// <summary>
		/// Создать <see cref="StrategyParam{T}"/>.
		/// </summary>
		/// <typeparam name="T">Тип значения параметра.</typeparam>
		/// <param name="strategy">Стратегия.</param>
		/// <param name="name">Название параметра.</param>
		/// <param name="initialValue">Первоначальное значение.</param>
		/// <returns>Параметр стратегии.</returns>
		public static StrategyParam<T> Param<T>(this Strategy strategy, string name, T initialValue = default(T))
		{
			return new StrategyParam<T>(strategy, name, initialValue);
		}
	}
}